package com.cw.jeeyt.service.converter.json;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.TeeOutputStream;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.lang.NonNull;

import com.cw.lang.common.constants.ControllerFlagConstant;
import com.cw.lang.common.utils.context.ThreadContextStoreUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.cw.lang.common.utils.StringUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * controller日志打印，由于基于controller的aop的话，不能打印json格式日志
 *
 * @author chenw
 * @version $$Id: LoggingFromHttpMessageConverter.java, v 0.1 2018/12/8 4:27 PM chenw Exp $$
 */
@Slf4j
public class LoggingFromHttpMessageConverter extends MappingJackson2HttpMessageConverter {

    public LoggingFromHttpMessageConverter(ObjectMapper objectMapper) {
        super(objectMapper);
    }

    @Override
    @NonNull
    public Object read(@NonNull Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException {
        String path = (String) ThreadContextStoreUtil.getInstance()
            .get(ControllerFlagConstant.REQUEST_PATH);
        // 如果path为空，或者是feign调用过程中，则不打印日志
        if (StringUtil.isBlank(path) || ThreadContextStoreUtil.getInstance()
            .get(ControllerFlagConstant.FEIGN_CODEC_PROCESSING) != null) {
            return super.read(type, contextClass, inputMessage);
        }
        byte[] content = IOUtils.toByteArray(inputMessage.getBody());
        log.info("请求[{}]的业务参数入参为:[{}]", path, new String(content, StandardCharsets.UTF_8));

        return super.read(type, contextClass, new HttpInputMessage() {
            @Override
            @NonNull
            public InputStream getBody() {
                return new ByteArrayInputStream(content);
            }

            @Override
            @NonNull
            public HttpHeaders getHeaders() {
                return inputMessage.getHeaders();
            }
        });
    }

    @Override
    protected void writeInternal(@NonNull Object object, Type type, HttpOutputMessage outputMessage)
    throws IOException, HttpMessageNotWritableException {
        String path = (String) ThreadContextStoreUtil.getInstance()
            .get(ControllerFlagConstant.REQUEST_PATH);

        // 如果path为空，或者是feign调用过程中，则不打印日志
        if (StringUtil.isBlank(path) || ThreadContextStoreUtil.getInstance()
            .get(ControllerFlagConstant.FEIGN_CODEC_PROCESSING) != null) {
            super.writeInternal(object, type, outputMessage);
        } else {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            // 两个输出流进行合并
            TeeOutputStream teeOutputStream = new TeeOutputStream(byteArrayOutputStream, outputMessage.getBody());
            super.writeInternal(object, type, new HttpOutputMessage() {
                @Override
                @NonNull
                public OutputStream getBody() {
                    return teeOutputStream;
                }

                @Override
                @NonNull
                public HttpHeaders getHeaders() {
                    return outputMessage.getHeaders();
                }
            });
            log.info("请求[{}]的出参为:[{}]", path, new String(byteArrayOutputStream.toByteArray(), StandardCharsets.UTF_8));
        }
    }
}
